#include "Data.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include "Tools.h"

int buffer_line(Rough* rough, FILE* config){
	char currentChar = 0;
	int i = 0;

	currentChar = fgetc(config);

	while(currentChar != '\n'){
		if(currentChar == EOF)
			return 0;
		rough->buffer[i] = currentChar;
		currentChar = fgetc(config);
		i++; 
	}
	rough->buffer[i] = '\0';
	return 1;
}

int convertAscii(char* line, int start, char end){
#define LOWER_NUM 48
#define UPPER_NUM 57
	int result = 0, i=start, lengh=0, j=0;
	while(line[i] != end && line[i] != '\0'){
		if(line[i] >= LOWER_NUM && line[i]<= UPPER_NUM){
			lengh++;	
		}
		i++;
	}
	for(j=0; j<lengh; j++){
		result += (line[start+j]-LOWER_NUM)*pow(10,lengh-j-1);
	}
	return result;
}

int nextCharPosition(char* line, int pos, char character){
	int posChar = pos;
	while(line[posChar] != character && line[posChar] != '\0'){
		posChar ++;
	}
	return posChar;
}

void parser_config(Rough* rough, int* nbValueStored){
	int index = 0;
	if(rough->buffer[0] != '#'){
		index = *nbValueStored;
		rough->d[index] = convertAscii(rough->buffer,
    						nextCharPosition(rough->buffer, 0, ':')+2,
						'\0');
		(*nbValueStored)++;
	}
}

void parser_monster(Rough* rough, int* nbValueStored){
	int i = 0, j = 0, index = 0;
	if(rough->buffer[0] == '$'){
		rough->nb_ennemy_vague[rough->vague] = *nbValueStored;
		rough->vague ++;
	}
	else if(rough->buffer[0] != '#'){
		index = *nbValueStored;
		i = nextCharPosition(rough->buffer, 0, ' ');
		
		for(j=0; j<i; j++){
			rough->mName[index][j] = rough->buffer[j];
		}
		rough->mName[index][i] = '\0';

		i++;
		rough->mLife[index] = convertAscii(rough->buffer, i, ' ');
		i = nextCharPosition(rough->buffer, i, ' ') + 1;
		rough->mSpeed[index] = convertAscii(rough->buffer, i, ' ');
		i = nextCharPosition(rough->buffer, i, ' ') + 1;
		rough->mType[index] = convertAscii(rough->buffer, i, ' ');
		i = nextCharPosition(rough->buffer, i, ' ') + 1;
		rough->mAnimation_speed[index] = convertAscii(rough->buffer, i, ' ');
		i = nextCharPosition(rough->buffer, i, ' ') + 1;
		rough->mPrice[index] = convertAscii(rough->buffer, i, '\0');
		(*nbValueStored)++;
	}
}

void parser_tower(Rough* rough, int* nbValueStored){
	int i = 0, j = 0, index = 0;
	if(rough->buffer[0] != '#'){
		index = *nbValueStored;
		i = nextCharPosition(rough->buffer, 0, ' ')+1;
		rough->tType_bullet[index] = convertAscii(rough->buffer, i, ' ');
		i = nextCharPosition(rough->buffer, i, ' ')+1;
		rough->tType_attack[index] = convertAscii(rough->buffer, i, ' ');
		i = nextCharPosition(rough->buffer, i, ' ')+1;
		rough->tDegat[index] = convertAscii(rough->buffer, i, ' ');
		i = nextCharPosition(rough->buffer, i, ' ')+1;
		rough->tCountdown[index] = convertAscii(rough->buffer, i, ' ');
		i = nextCharPosition(rough->buffer, i, ' ')+1;
		rough->tRange[index] = convertAscii(rough->buffer, i, ' ');
		i = nextCharPosition(rough->buffer, i, ' ')+1;
		rough->tSplash[index] = convertAscii(rough->buffer, i, ' ');
		i = nextCharPosition(rough->buffer, i, ' ')+1;
		rough->tSpeed[index] = convertAscii(rough->buffer, i, '\0');

		(*nbValueStored)++;
	}
}

void Read_And_Store_to_Rough_Data(Rough* rough){
	FILE* config = NULL;
	int nbValueStored = 0;

	config = fopen("CONFIG", "r");

	if(config == NULL){
		fprintf(stderr, "Error: File ./CONFIG is missing");
		exit(EXIT_FAILURE);
	}

	while(buffer_line(rough, config)){
		parser_config(rough, &nbValueStored);
	}

	nbValueStored = 0;
	config = fopen("MONSTER", "r");

	if(config == NULL){
		fprintf(stderr, "Error: File ./MONSTER is missing");
		exit(EXIT_FAILURE);
	}

	while(buffer_line(rough, config)){
		parser_monster(rough, &nbValueStored);
	}

	nbValueStored = 0;
	config = fopen("TOWER", "r");

	if(config == NULL){
		fprintf(stderr, "Error: File ./TOWER is missing");
		exit(EXIT_FAILURE);
	}

	while(buffer_line(rough, config)){
		parser_tower(rough, &nbValueStored);
	}
}

void GraphicData(Data* data, Rough* rough){
	int flag = SDL_DOUBLEBUF;
	data->graphic.window_dimension.x = rough->d[0];
	data->graphic.window_dimension.y = rough->d[1];
	data->graphic.bit_per_color = rough->d[2];
	data->graphic.fullscreen  = rough->d[3];
	data->graphic.hw_surface = rough->d[4];
	data->graphic.frames = rough->d[5];
	data->graphic.bullets = rough->d[6];
	if(data->graphic.hw_surface){
		flag = flag | SDL_HWSURFACE;
	}
	if(data->graphic.fullscreen){
		flag = flag | SDL_FULLSCREEN;
	}
	data->graphic.screen = SDL_SetVideoMode(data->graphic.window_dimension.x,
					      data->graphic.window_dimension.y,
					      data->graphic.bit_per_color,
					      flag);		
	SDL_WM_SetCaption("Tower Defense", NULL);
	data->graphic.back_ground = SDL_LoadBMP("Resources/BackGround.bmp");
}

void MapData(Data* data, Rough* rough){
	data->map.dimension.x =  rough->d[11];
	data->map.dimension.y =  rough->d[12];
	data->map.starting_block.x =  rough->d[13];
	data->map.starting_block.y =  rough->d[14];
	data->map.final_block.x =  rough->d[15];
	data->map.final_block.y =  rough->d[16];
	data->map.first_block.x =  rough->d[17];
	data->map.first_block.y = rough->d[18];
	data->map.starting.x = rough->d[19];
	data->map.starting.y = rough->d[20];
	data->map.final.x = rough->d[21];
	data->map.final.y = rough->d[22];
	data->map.dimension_case.x = rough->d[23];
	data->map.dimension_case.y = rough->d[24];
}

void GamingData(Data* data, Rough* rough){
	data->gaming.lifes = rough->d[25];
	data->gaming.startingG = rough->d[26];
}

void InitGMonster(Creep* pm, int nb_frames){
	int i;
        char *directory = malloc(DIRECTORY_SIZE + 1);
        char *extension = malloc(EXTENSION_SIZE + 1);
        char *image = malloc(DIRECTORY_SIZE + 3 + EXTENSION_SIZE + 1);

        extension = ".bmp";
        snprintf(directory, DIRECTORY_SIZE +1, "%s%s%s", "Resources/", pm->name, "/walkNorth/");
	for(i=0;i<nb_frames;i++){
                snprintf(image ,DIRECTORY_SIZE + 3 + EXTENSION_SIZE + 1, "%s%ld%s", directory, i, extension);
	        if((pm->walkNorth[i] = SDL_LoadBMP(image)) == NULL){
			fprintf(stderr, "Error: %s doesn't exist\n", image);
			exit(EXIT_FAILURE);
		}
                SDL_SetColorKey(pm->walkNorth[i], SDL_SRCCOLORKEY, SDL_MapRGB(pm->walkNorth[i]->format,255,0,255));
        }
        snprintf(directory, DIRECTORY_SIZE +1, "%s%s%s", "Resources/", pm->name, "/walkSouth/");
        for(i=0;i<nb_frames;i++){
                snprintf(image ,DIRECTORY_SIZE + 3 + EXTENSION_SIZE + 1, "%s%ld%s", directory, i, extension);
                if((pm->walkSouth[i] = SDL_LoadBMP(image)) == NULL){
			fprintf(stderr, "Error: %s doesn't exist\n", image);
			exit(EXIT_FAILURE);
		}
                SDL_SetColorKey(pm->walkSouth[i], SDL_SRCCOLORKEY, SDL_MapRGB(pm->walkSouth[i]->format,255,0,255));
        }
        snprintf(directory, DIRECTORY_SIZE +1, "%s%s%s", "Resources/", pm->name, "/walkEast/");
        for(i=0;i<nb_frames;i++){
                snprintf(image ,DIRECTORY_SIZE + 3 + EXTENSION_SIZE + 1, "%s%ld%s", directory, i, extension);
                if((pm->walkEast[i] = SDL_LoadBMP(image)) == NULL){
			fprintf(stderr, "Error: %s doesn't exist\n", image);
			exit(EXIT_FAILURE);
		}
                SDL_SetColorKey(pm->walkEast[i], SDL_SRCCOLORKEY, SDL_MapRGB(pm->walkEast[i]->format,255,0,255));
        }
        snprintf(directory, DIRECTORY_SIZE +1, "%s%s%s", "Resources/", pm->name, "/walkWest/");
        for(i=0;i<nb_frames;i++){
                snprintf(image ,DIRECTORY_SIZE + 3 + EXTENSION_SIZE + 1, "%s%ld%s", directory, i, extension);
                if((pm->walkWest[i] = SDL_LoadBMP(image)) == NULL){
			fprintf(stderr, "Error: %s doesn't exist\n", image);
			exit(EXIT_FAILURE); 
		}
                SDL_SetColorKey(pm->walkWest[i], SDL_SRCCOLORKEY, SDL_MapRGB(pm->walkWest[i]->format,255,0,255));
        }
	snprintf(directory, DIRECTORY_SIZE +1, "%s%s%s", "Resources/", pm->name, "/Stand/");
	for(i=0;i<nb_frames;i++){
		snprintf(image, DIRECTORY_SIZE + 3 + EXTENSION_SIZE + 1, "%s%ld%s", directory, i, extension);
		if((pm->stand[i] = SDL_LoadBMP(image)) == NULL){
			fprintf(stderr, "Error: %s doesn't exist\n", image);
			exit(EXIT_FAILURE);
		}
		SDL_SetColorKey(pm->stand[i], SDL_SRCCOLORKEY, SDL_MapRGB(pm->stand[i]->format, 255, 0, 255));
	}
}

void MonsterData(Data* data, Rough* rough){
	int i = 0 ;	
	int nb_creep = rough->nb_ennemy_vague[rough->vague-1];

	data->monster.creep = malloc((nb_creep)*sizeof(Creep));
	data->monster.vague = rough->vague;
	data->monster.creeps = malloc((rough->vague) * sizeof(int));
	for(i=0; i < rough->vague; i++){
		data->monster.creeps[i] = rough->nb_ennemy_vague[i];
	}


	for(i=0; i < nb_creep; i++){
		data->monster.creep[i].name = rough->mName[i];
		data->monster.creep[i].activ = 1;
		data->monster.creep[i].type = rough->mType[i];
		data->monster.creep[i].speed = (double)((double)rough->mSpeed[i])/100;
		data->monster.creep[i].life = rough->mLife[i];
		data->monster.creep[i].action = STAND;
		data->monster.creep[i].currentFrame = 0;
		data->monster.creep[i].out.x = rough->d[21];
		data->monster.creep[i].out.y = rough->d[22];
		data->monster.creep[i].goal.x = rough->d[15];
		data->monster.creep[i].goal.y = rough->d[16];
		data->monster.creep[i].current.x = rough->d[19];
		data->monster.creep[i].current.y = rough->d[20];
		data->monster.creep[i].animation_speed = rough->mAnimation_speed[i];
		data->monster.creep[i].animation_time = 0;
		data->monster.creep[i].price = rough->mPrice[i];
		data->monster.creep[i].walkNorth = malloc(data->graphic.frames*sizeof(SDL_Surface*));
		data->monster.creep[i].walkSouth = malloc(data->graphic.frames*sizeof(SDL_Surface*));
		data->monster.creep[i].walkEast = malloc(data->graphic.frames*sizeof(SDL_Surface*));
		data->monster.creep[i].walkWest = malloc(data->graphic.frames*sizeof(SDL_Surface*));
		data->monster.creep[i].stand = malloc(data->graphic.frames*sizeof(SDL_Surface*));
		InitGMonster(&(data->monster.creep[i]), data->graphic.frames);
	}
}


void TimeData(Data* data, Rough* rough){
	data->time.print = rough->d[7];
	data->time.frame = rough->d[8];
	data->time.spawn = rough->d[9];
	data->time.next_wave = rough->d[10];
	data->time.exec_time = 0;
	data->time.game_time = 0;
	data->time.paused_time = 0;
	data->time.last_print = 0;
	data->time.last_spawn = 0;
	data->time.wave = 0;
}

void MachineData(Data* data, Rough* rough){
	data->machine.main.cur = rough->d[47];
	data->machine.main.pre = rough->d[47];
	data->machine.pause.cur = rough->d[48];
	data->machine.pause.pre = rough->d[48];
	data->machine.menu.cur = rough->d[49];
	data->machine.menu.pre = rough->d[49];
	data->machine.game.cur = rough->d[50];
	data->machine.game.pre = rough->d[50];
	data->machine.creep.cur = rough->d[51];
	data->machine.creep.pre = rough->d[51];
}

void MenuData(Data* data, Rough* rough){
	data->menu.back_ground = SDL_LoadBMP("Resources/Menu.bmp");
	data->menu.selection = SDL_LoadBMP("Resources/Selection.bmp");
	data->menu.dimension.x = rough->d[52];
	data->menu.dimension.y = rough->d[53];
	data->menu.play.knot.x = rough->d[54] + (rough->d[0]-rough->d[52])/2;
	data->menu.play.knot.y = rough->d[55] + (rough->d[1]-rough->d[53])/2;
	data->menu.play.dim.x = rough->d[56];
	data->menu.play.dim.y = rough->d[57];
	data->menu.quit.knot.x = rough->d[58] + (rough->d[0]-rough->d[52])/2;
	data->menu.quit.knot.y = rough->d[59] + (rough->d[1]-rough->d[53])/2;
	data->menu.quit.dim.x = rough->d[60];
	data->menu.quit.dim.y = rough->d[61];
	data->menu.new_game.knot.x = rough->d[62] + (rough->d[0]-rough->d[52])/2;
	data->menu.new_game.knot.y = rough->d[63] + (rough->d[1]-rough->d[53])/2;
	data->menu.new_game.dim.x = rough->d[64];
	data->menu.new_game.dim.y = rough->d[65];

}

void TowerData(Data* data, Rough* rough){
	data->tower.towers = rough->d[27];

	data->tower.field.type = EMPTY;

	data->tower.missile.action.cur = STAND;
	data->tower.missile.action.pre = STAND;
	data->tower.missile.type = MISSILE;
	data->tower.missile.type_bullet = rough->tType_bullet[0];
	data->tower.missile.type_attack = rough->tType_attack[0];
	data->tower.missile.cost = 5;
	data->tower.missile.degat = rough->tDegat[0];
	data->tower.missile.countdown = rough->tCountdown[0];
	data->tower.missile.range = rough->tRange[0];
	data->tower.missile.time = 0;
	data->tower.missile.index_cible = -1;
	data->tower.missile.splash = (double)((double)rough->tSplash[0])/100;
	data->tower.missile.speed = (double)((double)rough->tSpeed[0])/100;
	data->tower.missile.tower_image = SDL_LoadBMP("Resources/Missile/Missile.bmp");
	data->tower.missile.bullet_image = SDL_LoadBMP("Resources/Missile/Bullet.bmp");
	data->tower.missile.index_bullet = 0;

	data->tower.mortar.action.cur = STAND;
	data->tower.mortar.action.pre = STAND;
	data->tower.mortar.type = MORTAR;
	data->tower.mortar.type_bullet = rough->tType_bullet[1];
	data->tower.mortar.type_attack = rough->tType_attack[1];
	data->tower.mortar.cost = 20;
	data->tower.mortar.degat = rough->tDegat[1];
	data->tower.mortar.countdown = rough->tCountdown[1];
	data->tower.mortar.range = rough->tRange[1];
	data->tower.mortar.time = 0;
	data->tower.mortar.index_cible = -1;
	data->tower.mortar.splash = ((double)rough->tSplash[1])/100;
	data->tower.mortar.speed = ((double)rough->tSpeed[1])/100;
	data->tower.mortar.tower_image = SDL_LoadBMP("Resources/Mortar/Mortar.bmp");
	data->tower.mortar.bullet_image = SDL_LoadBMP("Resources/Mortar/Bullet.bmp");
	data->tower.mortar.index_bullet = 0;
}

void InterfaceData(Data* data, Rough* rough){
	data->interface.interface = SDL_LoadBMP("Resources/Interface.bmp");
	SDL_SetColorKey(data->interface.interface, SDL_SRCCOLORKEY, SDL_MapRGB(data->interface.interface->format, 255, 0, 255));
	data->interface.play.knot.x = rough->d[27];
	data->interface.play.knot.y = rough->d[28];
	data->interface.play.dim.x = rough->d[29];
	data->interface.play.dim.y = rough->d[30];
	data->interface.pause.knot.x = rough->d[31];
	data->interface.pause.knot.y = rough->d[32];
	data->interface.pause.dim.x = rough->d[33];
	data->interface.pause.dim.y = rough->d[34];
	data->interface.mortar.knot.x = rough->d[35];
	data->interface.mortar.knot.y = rough->d[36];
	data->interface.mortar.dim.x = rough->d[37];
	data->interface.mortar.dim.y = rough->d[38];
	data->interface.missile.knot.x = rough->d[39];
	data->interface.missile.knot.y = rough->d[40];
	data->interface.missile.dim.x = rough->d[41];
	data->interface.missile.dim.y = rough->d[42];
	data->interface.menu.knot.x = rough->d[43];
	data->interface.menu.knot.y = rough->d[44];
	data->interface.menu.dim.x = rough->d[45];
	data->interface.menu.dim.y = rough->d[46];
}

void GameData(Data* data, Rough* rough){
	int i=0, j=0, k=0;

	data->game.lifes = rough->d[25];
	data->game.gold = rough->d[26];
	data->game.current_tower = data->tower.missile;
        data->game.map = malloc(rough->d[11]*sizeof(Node*));
	for(i=0; i<rough->d[11]; i++){
		data->game.map[i]= malloc(rough->d[12]*sizeof(Node));
	}
	for(j = 0; j < rough->d[11]; j++){
		for(k = 0; k < rough->d[12]; k++){
			data->game.map[j][k].tower.type = EMPTY;
		}
	}
	data->game.creep_current_nb = 0;
	data->game.wave_current_nb = 0;
}

void Rough_to_final(Data* data, Rough* rough){
	GraphicData(data, rough);
	MapData(data, rough);
	GamingData(data, rough);
	MonsterData(data, rough);
	TimeData(data, rough);
	MachineData(data, rough);
	MenuData(data, rough);
	TowerData(data, rough);
	InterfaceData(data, rough);
	GameData(data, rough);
}

void allocateMemory(Rough* rough){
	int i =0;
        rough->d = malloc(MAX_CONFIG*sizeof(int));
        rough->mLife = malloc(MAX_CREEP*sizeof(int));
        rough->mSpeed = malloc(MAX_CREEP*sizeof(int));
        rough->mType = malloc(MAX_CREEP*sizeof(int));
	rough->mAnimation_speed = malloc(MAX_CREEP*sizeof(int));
	rough->mPrice = malloc(MAX_CREEP*sizeof(int));
        rough->mName = malloc(MAX_CREEP*sizeof(char*));
	for(i=0; i<100; i++){
		rough->mName[i]= malloc(NAME_SIZE*sizeof(char));
	}
	rough->vague = 0;
	rough->nb_ennemy_vague = malloc(MAX_VAGUE * sizeof(int));
	rough->tType_bullet = malloc(MAX_TOWER*sizeof(int));
	rough->tType_attack = malloc(MAX_TOWER*sizeof(int));
	rough->tDegat = malloc(MAX_TOWER*sizeof(int));
	rough->tCountdown = malloc(MAX_TOWER*sizeof(int));
	rough->tRange = malloc(MAX_TOWER*sizeof(int));
	rough->tSplash = malloc(MAX_TOWER*sizeof(double));
	rough->tSpeed = malloc(MAX_TOWER*sizeof(double));
	rough->buffer = malloc(MAX_CHAR*sizeof(char));
}

void InitData(Data *data, Rough* rough){
	allocateMemory(rough);
	Read_And_Store_to_Rough_Data(rough);
	Rough_to_final(data, rough);
}

void DestroyRough(Rough* rough){
	free(rough->d);
	free(rough->mLife);
	free(rough->mSpeed);
	free(rough->mType);
	free(rough->mName);
	free(rough->nb_ennemy_vague);
	free(rough->tType_bullet);
	free(rough->tType_attack);
	free(rough->tDegat);
	free(rough->tCountdown);
	free(rough->tRange);
	free(rough->tSplash);
	free(rough->tSpeed);
	free(rough->buffer); 
}

void DestroyData(Data* data){
	int i=0, j=0; 
	SDL_FreeSurface(data->graphic.screen);
	SDL_FreeSurface(data->menu.back_ground);
	SDL_FreeSurface(data->interface.interface);
/*	for(i=0; i<data->gaming.creeps; i++){
		for(j=0; j<data->graphic.frames; j++){
			SDL_FreeSurface(data->monster.creep[i].walkNorth[j]);
			SDL_FreeSurface(data->monster.creep[i].walkSouth[j]);
			SDL_FreeSurface(data->monster.creep[i].walkEast[j]);
			SDL_FreeSurface(data->monster.creep[i].walkWest[j]);
			SDL_FreeSurface(data->monster.creep[i].stand[j]);	
		}
		free(data->monster.creep[i].walkNorth);
		free(data->monster.creep[i].walkSouth);
		free(data->monster.creep[i].walkEast);
		free(data->monster.creep[i].walkWest);
		free(data->monster.creep[i].stand);
	}
*/
	free(data->monster.creep);
	free(data->game.map); 
}
